#pragma once

#include "../../../Common/HkIncludes.h"
#include "../../Collision/Shape/HkpShape.h"

using namespace Microsoft::Xna::Framework;
using namespace Havok::Collision;

namespace Havok
{
	namespace Dynamics
	{
		///<summary>
		/// A list of all motion types. The motion type of a hkpRigidBody determines what
		/// happens when the rigid body is simulated. 
		///</summary>
		public enum struct HkpMotionType
		{
			Invalid = hkpMotion::MOTION_INVALID,
			
			///<summary>
			/// A fully-simulated, movable rigid body. At construction time the engine checks
			/// the input inertia and selects Sphere_Inertia or Box_Inertia as
			/// appropriate.
			///</summary>
			Dynamic = hkpMotion::MOTION_DYNAMIC,
			
			///<summary>
			/// Simulation is performed using a sphere inertia tensor. (A multiple of the
			/// Identity matrix). The highest value of the diagonal of the rigid body's
			/// inertia tensor is used as the spherical inertia.
			///</summary>
			Sphere_Inertia = hkpMotion::MOTION_SPHERE_INERTIA,
			
			///<summary>
			/// This is the same as Sphere_Inertia, except that simulation of the rigid
			/// body is "softened", which produces more stable results in large constrained
			/// systems.
			///</summary>
			Stabilized_Sphere_Inertia = hkpMotion::MOTION_STABILIZED_SPHERE_INERTIA,
			
			///<summary>
			/// Simulation is performed using a box inertia tensor. The non-diagonal elements
			/// of the inertia tensor are set to zero. This is slower than the
			/// Sphere_Inertia motions, however it can produce more accurate results,
			/// especially for long thin objects.
			///</summary>
			Box_Inertia = hkpMotion::MOTION_BOX_INERTIA,
			
			///<summary>
			/// This is the same as Box_Inertia, except that simulation of 	the rigid
			/// body is "softened", which produces more stable results in large constrained
			/// systems.
			///</summary>
			Stabilized_Box_Inertia = hkpMotion::MOTION_STABILIZED_BOX_INERTIA,
			
			///<summary>
			/// Simulation is not performed as a normal rigid body. During a simulation step,
			/// the velocity of the rigid body is used to calculate the new position of the
			/// rigid body, however the velocity is NOT updated. The user can keyframe a rigid
			/// body by setting the velocity of the rigid body to produce the desired keyframe
			/// positions. The hkpKeyFrameUtility class can be used to simply apply keyframes
			/// in this way. The velocity of a keyframed rigid body is NOT changed by the
			/// application of impulses or forces. The keyframed rigid body has an infinite
			/// mass when viewed by the rest of the system.
			///</summary>
			Keyframed = hkpMotion::MOTION_KEYFRAMED,
			
			///<summary>
			/// This motion type is used for the static elements of a game scene, e.g. the
			/// landscape. Fixed rigid bodies are treated in a special way by the system. They
			/// have the same effect as a rigid body with a motion of type Keyframed
			/// and velocity 0, however they are much faster to use, incurring no simulation
			/// overhead, except in collision with moving bodies.
			///</summary>
			Fixed = hkpMotion::MOTION_FIXED,
			
			///<summary>
			/// A box inertia motion which is optimized for thin boxes and has less stability problems.
			///</summary>
			Thin_Box_Inertia = hkpMotion::MOTION_THIN_BOX_INERTIA,
		};
		
		///<summary>
		/// This type is used to specify the quality type for collidables (used by hkpRigidBody)
		/// This is mainly used to identify objects, which require the more expensive
		/// continuous simulation (compared to the faster, Havok2 style discrete) simulation.
		/// See the continuous simulation user guide, of the hkpCollisionDispatcher for more details.
		///</summary>
		public enum struct HkpCollidableQualityType
		{
			///<summary>
			/// Invalid or unassinged type. If you add a hkpRigidBody to the hkpWorld,
			/// this type automatically gets converted to either
			/// Fixed, Keyframed or Debris.
			///</summary>
			Invalid = HK_COLLIDABLE_QUALITY_INVALID,
			
			///<summary>
			/// Use this for fixed bodies.
			///</summary>
			Fixed = HK_COLLIDABLE_QUALITY_FIXED,

			///<summary>
			/// Use this for moving objects with infinite mass. 
			///</summary>
			Keyframed = HK_COLLIDABLE_QUALITY_KEYFRAMED,

			///<summary>
			/// Use this for all you debris objects.
			///</summary>
			Debris = HK_COLLIDABLE_QUALITY_DEBRIS,

			///<summary>
			/// Use this for moving bodies, which should not leave the world, 
			/// but you rather prefer those objects to tunnel through the world than
			/// dropping frames because the engine.
			///</summary>
			Moving = HK_COLLIDABLE_QUALITY_MOVING,

			///<summary>
			/// Use this for all objects, which you cannot afford to tunnel through
			/// the world at all.
			///</summary>
			Critical = HK_COLLIDABLE_QUALITY_CRITICAL,

			///<summary>
			/// Use this for very fast objects.
			///</summary>
			Bullet = HK_COLLIDABLE_QUALITY_BULLET,

			///<summary>
			/// Use this for rigid body character controllers.
			///</summary>
			Character = HK_COLLIDABLE_QUALITY_CHARACTER,
		};
		
		///<summary>
		/// A list of possible solver deactivation settings. This value defines how the
		/// solver deactivates objects. The solver works on a per object basis. 	
		/// Note: Solver deactivation does not save CPU, but reduces creeping of
		/// movable objects in a pile quite dramatically.
		///</summary>
		public enum struct HkpSolverDeactivation
		{
			Invalid = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_INVALID,
			
			///<summary>No solver deactivation.</summary>
			Off = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_OFF,
			
			///<summary>Very conservative deactivation, typically no visible artifacts.</summary>
			Low = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_LOW,
			
			///<summary>Normal deactivation, no serious visible artifacts in most cases.</summary>
			Medium = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_MEDIUM,
			
			///<summary>Fast deactivation, visible artifacts.</summary>
			High = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_HIGH,

			///<summary>Very fast deactivation, visible artifacts.</summary>
			Max = hkpRigidBodyCinfo::SOLVER_DEACTIVATION_MAX,
		};
		
		///<remarks>
		/// A class containing all the information needed to construct a rigid body.
		///</remarks>
		public ref class HkpRigidBodyCinfo
		{
		public:
			HkpRigidBodyCinfo(void);

			void CalculateBoxInertiaTensor(Vector3 halfExtents, float mass);

			void CalculateSphereInertiaTensor(float radius, float mass);
			
			///<summary>
			/// The initial position of the body.
			/// This defaults to 0,0,0.
			///</summary>
			property Vector3 Position
			{
			public:
				virtual void set(Vector3 value);
				virtual Vector3 get();
			}
			
			///<summary>
			/// The initial rotation of the body.
			/// This defaults to the Identity quaternion.
			///</summary>
			property Quaternion Rotation
			{
				virtual void set(Quaternion value);
				virtual Quaternion get();
			}
			
			///<summary>
			/// The initial linear velocity of the body.
			/// This defaults to 0,0,0.
			///</summary>
			property Vector3 LinearVelocity
			{
				virtual void set(Vector3 value);
				virtual Vector3 get();
			}
			
			///<summary>
			/// The initial angular velocity of the body.
			/// This defaults to 0,0,0.
			///</summary>
			property Vector3 AngularVelocity
			{
				virtual void set(Vector3 value);
				virtual Vector3 get();
			}
			
			///<summary>
			/// The center of mass in the local space of the rigid body.
			/// This defaults to 0,0,0.
			///</summary>
			property Vector3 CenterOfMass
			{
			public:
				virtual void set(Vector3 value);
				virtual Vector3 get();
			}
			
			///<summary>
			/// The mass of the body.
			/// This defaults to 1.
			///</summary>
			property float Mass
			{
			public:
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The initial linear damping of the body.
			/// This defaults to 0.
			///</summary>
			property float LinearDamping
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The initial angular damping of the body.
			/// This defaults to 0.05.
			///</summary>
			property float AngularDamping
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The initial friction of the body.
			/// This defaults to 0.5.
			///</summary>
			property float Friction
			{
			public:
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The initial restitution of the body.
			/// This defaults to 0.4.
			/// If the restitution is not 0.0 the object will need extra CPU
			/// for all new collisions. Try to set restitution to 0 for maximum 
			/// performance (e.g. collapsing buildings)
			///</summary>
			property float Restitution
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The maximum linear velocity of the body (in m/s).
			/// This defaults to 200. 
			///</summary>
			property float MaxLinearVelocity
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The maximum angular velocity of the body (in rad/s).
			/// This defaults to 200.
			///</summary>
			property float MaxAngularVelocity
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The maximum allowed penetration for this object. The default is -1.
			/// This is a hint to the engine to see how much CPU the engine should
			/// invest to keep this object from penetrating. A good choice is 5% - 20% of the
			/// smallest diameter of the object.  Setting the initial value less than zero
			/// allows the penetration depth to be estimated by the RigidBody upon creation.
			/// This estimated value is 1/5th of the smallest dimension of the object's radius. 
			///</summary>
			property float AllowedPenetrationDepth
			{
				virtual void set(float value);
				virtual float get();
			}
			
			///<summary>
			/// The initial motion type of the body.
			/// This defaults to HkpMotionType.Dynamic
			///</summary>
			property HkpMotionType MotionType
			{
			public:
				virtual void set(HkpMotionType value);
				virtual HkpMotionType get();
			}
			
			///<summary>
			/// Allows you to enable an extra single object deactivation schema. 
			/// That means the engine will try to "deactivate" single objects (not just entire islands)
			/// if those objects get very slow.
			/// This does not save CPU, however it can reduce small movements in big stacks of objects dramatically. 
			/// This defaults to Low.
			///</summary>
			property HkpSolverDeactivation SolverDeactivation
			{
				virtual void set(HkpSolverDeactivation value);
				virtual HkpSolverDeactivation get();
			}
			
			///<summary>
			/// The quality type, used to specify when to use continuous physics.
			/// This defaults to Invalid.
	 		/// If you add a hkpRigidBody to the hkpWorld, this type automatically gets converted to either
		    /// Fixed, Keyframed or Debris.
			///</summary>
			property HkpCollidableQualityType QualityType
			{
				virtual void set(HkpCollidableQualityType value);
				virtual HkpCollidableQualityType get();
			}
			
			///<summary>
			/// This is a user flag which you can set to give you a hint as to which objects to remove from
			/// the simulation if the memory overhead becomes too high. It defaults to 0.
			///</summary>
			property signed char AutoRemoveLevel
			{
				virtual void set(signed char value);
				virtual signed char get();
			}
			
			///<summary>
			/// The collision detection representation for this entity.
			/// This defaults to NULL, and must be set before constructing a HkpRigidBody.
			///</summary>
			property HkpShape^ Shape
			{
			public:
				virtual void set(HkpShape^ value);
			}

			hkpRigidBodyCinfo* m_info;
		};
	}
}
